package lc.animation;

import java.util.ArrayList;
import java.util.logging.Logger;

import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.Spatial;

public class AnimationInstance {

	private static final Logger logger = Logger.getLogger(AnimationInstance.class.getName());

	private Animation animation;
	private float duration;
	private Spatial target;
	private float position = 0.0f;
	private float speed = 1.0f;
	private ArrayList<AnimationInstance> children = new ArrayList<AnimationInstance>();

	/**
	 * Create an animation instance to be able to animate a node (hierarchy) based on a loaded
	 * set of animation data.
	 * @param target The root of the node tree to animate.
	 * @param animation The actual animation to apply to the node tree.
	 * @param recursive Whether to actually match up children, or just apply to this one node.
	 */
	public AnimationInstance(Spatial target, Animation animation, boolean recursive) {
		this.target = target;
		this.animation = animation;
		this.duration = animation.getDuration();
		keyframe.translation = new Vector3f(target.getLocalTranslation());
		keyframe.rotation = new Quaternion(target.getLocalRotation());
		keyframe.scale = new Vector3f(target.getLocalScale());
		if (recursive && target instanceof Node && animation.getChildren().size() > 0) {
			Node n = (Node)target;
			for (Animation a : animation.getChildren()) {
				Spatial cld = getChildNoCase(n, a.getName());
				if (cld != null) {
					children.add(new AnimationInstance(cld, a, true));
				}
				else {
					logger.warning("Could not find child for animation " + a.getName());
				}
			}
		}
	}

	final Spatial getChildNoCase(Node n, String name) {
		for (Spatial c : n.getChildren()) {
			if (name.equalsIgnoreCase(c.getName()))
				return c;
		}
		return null;
	}

	Keyframe keyframe = new Keyframe();

	public void updateTarget() {
		animation.sample(position, keyframe);
		target.setLocalScale(keyframe.scale);
		target.setLocalRotation(keyframe.rotation);
		target.setLocalTranslation(keyframe.translation);
		target.updateWorldVectors();
		for (AnimationInstance ai : children) {
			ai.updateTarget();
		}
	}

	public Animation getAnimation() {
		return animation;
	}

	public Spatial getTarget() {
		return target;
	}

	public float getPosition() {
		return position;
	}

	public void setPosition(float position) {
		this.position = position;
		for (AnimationInstance a : children)
			a.setPosition(position);
	}

	public float getSpeed() {
		return speed;
	}

	public void setSpeed(float speed) {
		this.speed = speed;
	}

	public ArrayList<AnimationInstance> getChildren() {
		return children;
	}

	public void advance(float realTime) {
		if (duration == 0)
			return;
		this.position += realTime * speed;
		while (this.position < 0)
			this.position += duration;
		while (this.position >= duration)
			this.position -= duration;
		for (AnimationInstance ai : children)
			ai.setPosition(this.position);
	}

}

